package com.firsteapps.mobile.android.puzzle.game;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Vector;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.widget.TextView;

import com.firsteapps.mobile.android.puzzle.BaseActivity;
import com.firsteapps.mobile.android.puzzle.HighScore;
import com.firsteapps.mobile.android.puzzle.R;
import com.firsteapps.mobile.android.puzzle.RunOut;
import com.firsteapps.mobile.android.puzzle.util.Consts;
import com.firsteapps.mobile.android.puzzle.util.Utilities;

public class Helper {
	static long secondInMillis = 1000;
	static long minuteInMillis = secondInMillis * 60;
	static long hourInMillis = minuteInMillis * 60;
	static long dayInMillis = hourInMillis * 24;

	public static int getScore(int movesCount, int timePassed, int size) {
		int movesScore = getMovesScore(movesCount, size);
		int timeScore = getTimeScore(timePassed, size);
		return movesScore * timeScore * (size + 8) / 16000;
	}

	private static int getMovesScore(int moves, int n) {
		if (moves < 3 * n * n) {
			return 1000;
		} else if (moves > n * n * n * n) {
			return 1;
		} else {
			return getElementScore(3 * n * n, n * n * n * n, moves);
		}
	}

	private static int getTimeScore(int time, int n) {
		if (time < 3 * n * n) {
			return 1000;
		} else if (time > n * n * n * n) {
			return 1;
		} else {
			return getElementScore(3 * n * n, n * n * n * n, time);
		}
	}

	private static int getElementScore(int value1, int value2, int n) {
		return 1000 - (n - value1) * 999 / (value2 - value1);
	}

	public static HighScore getHighScore(String scoreString) {
		String[] scoreData = scoreString.split(Consts.FILENAME_SPLITTER);
		return new HighScore(scoreData[0], Integer.parseInt(scoreData[1]), Integer.parseInt(scoreData[2]),
				Integer.parseInt(scoreData[3]));
	}

	public static void autosolvePuzzle(final BaseActivity activity, final String infoPath, final PuzzleInfo info) {
		if (info.isAutosolvable()) {
			Helper.doMessageDialog(activity, "Auto Solve", "Are you sure you want to autosolve the puzzle?",
					new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							if (Helper.updateAccountBalance(activity, Consts.FILE_NAME_ACCOUNT_BALANCE, -1)) {
								info.setCompleted(true);
								Helper.saveOngoingPuzzle(activity, infoPath, info);
								Intent myIntent = new Intent(activity, RunOut.class);
								myIntent.putExtra(Consts.INFO_RUNOUT_TYPE, Consts.RUNOUT_NONE);
								myIntent.putExtra(Consts.PUZZLE_FILE_NAME, infoPath);
								activity.startActivity(myIntent);
								activity.finish();
								activity.overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
							}
						}
					}, true);
		} else {
			Helper.doMessageDialog(activity, "Auto Solve", "The puzzle is not autosolvable");
		}
	}

	public static void resetSelectedItem(boolean[] items) {
		for (int i = 0; i < items.length; i++) {
			items[i] = false;
		}
	}

	public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
		// Raw height and width of image
		final int height = options.outHeight;
		final int width = options.outWidth;
		int inSampleSize = 1;

		if (height > reqHeight || width > reqWidth) {
			if (width > height) {
				inSampleSize = Math.round((float) height / (float) reqHeight);
			} else {
				inSampleSize = Math.round((float) width / (float) reqWidth);
			}
		}
		return inSampleSize;
	}

	public static Bitmap decodeBitmapFromPath(String path, int reqWidth, int reqHeight) {

		// First decode with inJustDecodeBounds=true to check dimensions
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(path, options);

		// Calculate inSampleSize
		options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

		// Decode bitmap with inSampleSize set
		options.inJustDecodeBounds = false;
		return BitmapFactory.decodeFile(path, options);
	}

	public static boolean deleteFolder(File dir) {
		if (dir.isDirectory()) {
			String[] children = dir.list();
			for (int i = 0; i < children.length; i++) {
				boolean success = deleteFolder(new File(dir, children[i]));
				if (!success) {
					return false;
				}
			}
		}
		return dir.delete();
	}

	public static void deletePuzzle(Context context, String puzzleName, String userName) {
		PuzzleInfo info = Helper.loadCreatedPuzzle(context, puzzleName);

		Helper.unRegisterPuzzle(context, userName
				+ (info.isCompleted() ? Consts.FOLDER_NAME_COMPLETED_PUZZLES : Consts.FOLDER_NAME_INCOMPLETE_PUZZLES), puzzleName);

		deleteFile(context, info.getFile());
		if (info.getAlternativeImage() != null) {
			deleteFile(context, info.getAlternativeImage());
		}

		deleteFile(context, puzzleName);
	}

	public static void deleteFile(Context context, String fileName) {
		File file = new File(context.getFilesDir() + "/" + fileName);
		file.delete();
	}

	public static boolean saveInternalFileToExternalStorage(Context context, String internalFileName, File target) {
		FileOutputStream fos = null;
		FileInputStream fis = null;
		try {

			fis = context.openFileInput(internalFileName);
			fos = new FileOutputStream(target);
			int BUFF_SIZE = 1024;
			byte[] buff = new byte[BUFF_SIZE];
			int byteCount = 0;
			while ((byteCount = fis.read(buff, 0, BUFF_SIZE)) > 0) {
				fos.write(buff, 0, byteCount);

			}
			return true;
		} catch (FileNotFoundException e) {
			Helper.manageException(e, context);
		} catch (IOException e) {
			Helper.manageException(e, context);
		} finally {
			try {
				if (fos != null)
					fos.close();
				if (fis != null)
					fis.close();
			} catch (IOException e) {
				Helper.manageException(e, context);
			}
		}
		return false;
	}

	public static File getExternalFolder(Context context, String subFolderName) {
		File folder = getExternalFolder(context);
		if (folder == null)
			return null;

		File subFolder = new File(folder.getAbsolutePath() + "/" + subFolderName);
		if (!subFolder.exists())
			subFolder.mkdirs();
		return subFolder;
	}

	private static File getExternalFolder(Context context) {
		if (!Helper.isExternalStorageWritable()) {
			Helper.doMessageDialog(context, context.getString(R.string.error), context.getString(R.string.storage_unavailable));
			return null;
		}
		return Environment.getExternalStorageDirectory();
	}

	private static String getCompressedPuzzleFileName(Context context, File subFolder) {
		int idx = 1;
		File file;
		do {
			file = new File(subFolder.getAbsolutePath()
					+ String.format(Helper.getUserName("/" + ((BaseActivity) context).getUserName()) + "_Puzzle_%d"
							+ Consts.FILE_TYPE_COMPRESSED, idx++));
		} while (file.exists());
		return file.getAbsolutePath();
	};

	public static String getUserName(String user) {
		String[] userData = user.split(Consts.FILENAME_SPLITTER);
		if (userData.length == 2)
			return userData[0];

		return null;
	}

	public static void doMessageDialog(Context context, String title, String message) {
		doMessageDialog(context, title, message, null, false);
	}

	public static void doMessageDialog(Context context, String title, String message, OnClickListener onClick,
			boolean negativeChoise) {
		Thread contextThread = context.getMainLooper().getThread();
		if (contextThread != Thread.currentThread())
			return;

		AlertDialog.Builder builder = new AlertDialog.Builder(context).setTitle(title).setMessage(message)
				.setPositiveButton(android.R.string.ok, onClick);
		if (negativeChoise) {
			builder.setNegativeButton(android.R.string.cancel, new OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
					dialog.dismiss();
				}
			});
		}
		builder.create().show();
	}

	public static void saveOngoingPuzzle(Context context, String fileName, PuzzleInfo puzzleInfo) {
		System.out.println(fileName);
		FileOutputStream fos = null;
		ObjectOutputStream oos = null;
		try {
			fos = Helper.openOutputStream(context, fileName);
			oos = new ObjectOutputStream(fos);
			oos.writeObject(puzzleInfo);
		} catch (IOException e) {
			e.printStackTrace();
			manageException(e, context);
			return;
		} finally {
			try {
				if (oos != null)
					oos.close();
				if (fos != null)
					fos.close();
			} catch (IOException e) {
				e.printStackTrace();
				manageException(e, context);
			}
		}
	}

	public static String saveCreatedPuzzle(Context context, PuzzleInfo puzzleInfo, String destFolder) {
		String infoFileName = destFolder + "/" + Helper.getPuzzleFileName(context, Consts.FILE_TYPE_INFO, destFolder);
		infoFileName += Consts.FILENAME_SPLITTER + puzzleInfo.getCreationDate() + Consts.FILENAME_SPLITTER
				+ (puzzleInfo.isAutosolvable() ? "YES" : "NO");
		saveOngoingPuzzle(context, infoFileName, puzzleInfo);
		return infoFileName;
	}

	public static FileOutputStream openOutputStream(Context context, String fileName) throws FileNotFoundException {
		return new FileOutputStream(context.getFilesDir() + "/" + fileName);
	}

	public static FileInputStream openInputStream(Context context, String fileName) throws FileNotFoundException {
		return new FileInputStream(context.getFilesDir() + "/" + fileName);
	}

	public static PuzzleInfo loadCreatedPuzzle(Context context, String fileName) {
		PuzzleInfo info = null;

		ObjectInputStream ois = null;
		FileInputStream fis = null;
		try {
			fis = Helper.openInputStream(context, fileName);
			ois = new ObjectInputStream(fis);
			info = (PuzzleInfo) ois.readObject();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} finally {
			try {
				if (ois != null)
					ois.close();
				if (fis != null)
					fis.close();
			} catch (IOException e) {
				e.printStackTrace();
				manageException(e, context);
			}
		}
		return info;
	}

	public static String getPuzzleMetaFile(String puzzleFile, int puzzleSize) {
		return puzzleFile + Integer.toString(puzzleSize) + ".meta";
	}

	public static String getPuzzleFileName(Context context, String fileType, String sourceFolder) {
		int number = 1;
		String fileName;
		do {
			fileName = String.format("Puzzle_%d", number++) + fileType;

		} while (existPuzzleFile(context, fileName, fileType, sourceFolder));
		return fileName;
	}

	public static boolean existPuzzleFile(Context context, String fileName, String fileType, String sourceFolder) {
		String[] files = Helper.getPuzzleFiles(context, fileType, sourceFolder);
		for (String s : files) {
			if (fileType.equals(Consts.FILE_TYPE_INFO)) {
				String[] nameAttrs = s.substring(s.lastIndexOf("/") + 1).split(Consts.FILENAME_SPLITTER);
				s = nameAttrs[0];
			}
			if (s.contains(fileName)) {
				return true;
			}
		}
		return false;
	}

	public static String[] getPuzzleFiles(Context context, final String fileType, String sourceFolder) {
		if (sourceFolder == null)
			return new String[0];

		File source = new File(context.getFilesDir() + "/" + sourceFolder);
		if (!source.exists()) {
			source.mkdirs();
			return new String[0];
		}

		String[] files = source.list(new FilenameFilter() {
			@Override
			public boolean accept(File dir, String filename) {
				return filename.contains(fileType);
			}
		});

		for (int i = 0; i < files.length; i++) {
			files[i] = sourceFolder + "/" + files[i];
		}

		return files;
		// Vector<String> puzzleFiles = new Vector<String>();
		// for (String file : files) {
		// if (file.contains(fileType))
		// puzzleFiles.add(file);
		// }
		// String[] ret = new String[0];
		// return puzzleFiles.toArray(ret);
	}

	public static Bitmap getBitmap(Context context, String file) {
		FileInputStream fis;
		Bitmap bmp = null;
		try {
			fis = Helper.openInputStream(context, file);
			bmp = BitmapFactory.decodeStream(fis);
			fis.close();
		} catch (IOException e) {
			manageException(e, context);
		}
		return bmp;
	}

	public static byte[] getData(Context context, String file) {
		FileInputStream fis;
		int BUFF_SIZE = 1024;

		try {
			fis = context.openFileInput(file);
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			byte[] buff = new byte[BUFF_SIZE];
			int byteCount = 0;
			while ((byteCount = fis.read(buff, 0, BUFF_SIZE)) > 0) {
				out.write(buff, 0, byteCount);
			}
			fis.close();
			return out.toByteArray();
		} catch (FileNotFoundException e) {
			manageException(e, context);
		} catch (IOException e) {
			manageException(e, context);
		}
		return new byte[0];
	}

	public static String getElapsedTime(long duration) {

		long elapsedDays = duration / dayInMillis;
		duration = duration % dayInMillis;

		long elapsedHours = duration / hourInMillis;
		duration = duration % hourInMillis;

		long elapsedMinutes = duration / minuteInMillis;
		duration = duration % minuteInMillis;

		long elapsedSeconds = duration / secondInMillis;

		if (elapsedDays == 0 && elapsedHours == 0)
			return String.format("%d:%d", elapsedMinutes, elapsedSeconds);
		if (elapsedDays == 0)
			return String.format("%d:%d:%d", elapsedHours, elapsedMinutes, elapsedSeconds);

		return String.format("%d - %dh - %dm - %ds", elapsedDays, elapsedHours, elapsedMinutes, elapsedSeconds);
	}

	public static boolean isExternalStorageWritable() {
		String state = Environment.getExternalStorageState();

		return Environment.MEDIA_MOUNTED.equals(state);
	}

	public static void manageException(Exception e, Context context) {
		doMessageDialog(context, context.getString(R.string.error), e.getLocalizedMessage());

	}

	public static String[] getExternalPuzzles(Context context) {
		Vector<String> files = new Vector<String>();
		File root = getExternalFolder(context);
		File dismissFile = Helper.getExternalFolder(context, Consts.SHARED_PUZZLES_FOLDER);

		if (dismissFile != null) {
			addFiles(root, files, dismissFile.getAbsolutePath());
		} else
			addFiles(root, files);

		return files.toArray(new String[files.size()]);
	}

	private static void addFiles(File root, Vector<String> files, String dismissPath) {
		if (root == null || root.getAbsolutePath().equals(dismissPath))
			return;

		File[] listFiles = root.listFiles();
		if (listFiles == null)
			return;
		for (File f : listFiles) {
			if (f.isDirectory())
				addFiles(f, files, dismissPath);
			else if (f.getName().endsWith(Consts.FILE_TYPE_COMPRESSED))
				files.add(f.getAbsolutePath());
		}
	}

	private static void addFiles(File root, Vector<String> files) {
		if (root == null)
			return;
		File[] listFiles = root.listFiles();
		if (listFiles == null)
			return;
		for (File f : listFiles) {
			if (f.isDirectory())
				addFiles(f, files);
			else if (f.getName().endsWith(Consts.FILE_TYPE_COMPRESSED))
				files.add(f.getAbsolutePath());
		}
	}

	public static String saveGalleryImage(Context context, StringBuilder messages, String file, int imageMode, String destFolder) {
		File source = new File(file);
		FileOutputStream fos = null;
		FileInputStream fis = null;
		String targetFileName = destFolder + "/";
		try {
			if (imageMode == Consts.SELECT_ALTERNATIVE_GALLERY_REQUEST_CODE)
				targetFileName += Helper.getPuzzleFileName(context, Consts.FILE_TYPE_ALTERNATIVE, destFolder);
			else
				targetFileName += Helper.getPuzzleFileName(context, Consts.FILE_TYPE_PUZZLE, destFolder);

			fis = new FileInputStream(source);
			fos = Helper.openOutputStream(context, targetFileName);
			Helper.copyFile(fis, fos);
		} catch (Exception e) {
			if (messages.length() > 0)
				messages.append("\r\n");
			messages.append(e.getLocalizedMessage());
		} finally {
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					if (messages.length() > 0)
						messages.append("\r\n");
					messages.append(e.getLocalizedMessage());
				}
			}
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					if (messages.length() > 0)
						messages.append("\r\n");
					messages.append(e.getLocalizedMessage());
				}
			}
		}
		return targetFileName;
	}

	public static String importFile(Context context, StringBuffer messages, String sourceFile, String fileType, String destFolder) {
		FileOutputStream fos = null;
		FileInputStream fis = null;
		try {
			fis = Helper.openInputStream(context, sourceFile);
			String targetFileName = destFolder + "/" + Helper.getPuzzleFileName(context, fileType, destFolder);
			fos = Helper.openOutputStream(context, targetFileName);
			Helper.copyFile(fis, fos);
			return targetFileName;
		} catch (Exception e) {
			if (messages.length() > 0)
				messages.append("\r\n");
			messages.append(e.getLocalizedMessage());
		} finally {
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					if (messages.length() > 0)
						messages.append("\r\n");
					messages.append(e.getLocalizedMessage());
				}
			}
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					if (messages.length() > 0)
						messages.append("\r\n");
					messages.append(e.getLocalizedMessage());
				}
			}
		}
		return null;
	}

	public static void copyFile(FileInputStream fis, File out) throws Exception {
		FileOutputStream fos = new FileOutputStream(out);
		copyFile(fis, fos);
		fos.close();
	}

	public static void copyFile(FileInputStream fis, FileOutputStream fos) throws Exception {
		byte[] buf = new byte[1024];
		int i = 0;
		while ((i = fis.read(buf)) != -1) {
			fos.write(buf, 0, i);
		}
	}

	public static void safeDeleteFile(Context context, String file) {
		try {
			context.deleteFile(file);
		} catch (Exception e) {
		}
	}

	public static String[] getImageRealPathFromURI(Uri contentUri, Activity myActivity) {
		Cursor cursor = null;
		String[] proj = { MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID, MediaStore.Images.ImageColumns.ORIENTATION };
		cursor = myActivity.managedQuery(contentUri, proj, // Which columns to
															// return
				null, // WHERE clause; which rows to return (all rows)
				null, // WHERE clause selection arguments (none)
				null); // Order-by clause (ascending by name)
		int file_ColumnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
		int orientation_ColumnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.ORIENTATION);
		if (cursor.moveToFirst()) {
			int orientation = cursor.getInt(orientation_ColumnIndex);
			Log.e("the image orientation", "" + orientation);
			String imagePath = cursor.getString(file_ColumnIndex);

			return new String[] { imagePath, "" + orientation };
		}
		return null;
	}

	public static void shareCurrentPuzzle(Context context, String puzzleFileName, PuzzleInfo info) {
		if (info == null) {
			Helper.doMessageDialog(context, "Share Puzzle", "Unable to load selected puzzle");
		} else {
			File destPath = Helper.getExternalFolder(context, Consts.SHARED_PUZZLES_FOLDER);
			if (destPath == null)
				return;

			String destFile = Helper.getCompressedPuzzleFileName(context, destPath);

			String[] files;
			if (info.getAlternativeImage() != null) {
				files = new String[] { puzzleFileName, info.getFile(), info.getAlternativeImage() };
			} else {
				files = new String[] { puzzleFileName, info.getFile() };
			}

			Helper.compressFiles(context, files, destFile);
			Utilities.email(context, "someone@email.com", "", "Subject", "Email Body", new String[] { destFile });
		}
	}

	public static void shareCurrentPuzzle(Context context, String puzzleFileName) {
		PuzzleInfo info = Helper.loadCreatedPuzzle(context, puzzleFileName);
		shareCurrentPuzzle(context, puzzleFileName, info);
	}

	public static void compressFiles(Context context, String[] files, String destPath) {
		try {
			BufferedInputStream origin = null;
			FileOutputStream dest = new FileOutputStream(destPath);

			ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));

			byte data[] = new byte[Consts.BUFFER];

			for (int i = 0; i < files.length; i++) {
				Log.v("Compress", "Adding: " + files[i]);
				FileInputStream fi = openInputStream(context, files[i]);
				origin = new BufferedInputStream(fi, Consts.BUFFER);
				ZipEntry entry = new ZipEntry(files[i].substring(files[i].lastIndexOf("/") + 1));
				out.putNextEntry(entry);
				int count;
				while ((count = origin.read(data, 0, Consts.BUFFER)) != -1) {
					out.write(data, 0, count);
				}
				origin.close();
			}
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void decompress(Context context, String sourcePath, String destPath, boolean isTemp) {
		FileInputStream fin = null;
		try {
			fin = new FileInputStream(sourcePath);
			decompress(context, fin, destPath, isTemp);
		} catch (FileNotFoundException e) {
			Log.e("Decompress", e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				fin.close();
			} catch (IOException e) {
				Log.e("Decompress", e.getMessage());
				e.printStackTrace();
			}
		}
	}

	public static void decompress(Context context, InputStream in, String destPath, boolean isTemp) {
		FileOutputStream fout = null;
		try {
			ZipInputStream zin = new ZipInputStream(new BufferedInputStream(in));
			ZipEntry ze = null;
			while ((ze = zin.getNextEntry()) != null) {
				Log.v("Decompress", "Decompressing " + ze.getName());

				if (ze.getName().contains(Consts.FILE_TYPE_ALTERNATIVE))
					fout = Helper.openOutputStream(context, destPath + "/"
							+ (isTemp ? "puzzle" + Consts.FILE_TYPE_ALTERNATIVE : ze.getName()));

				if (ze.getName().contains(Consts.FILE_TYPE_INFO))
					fout = Helper.openOutputStream(context,
							destPath + "/" + (isTemp ? "puzzle" + Consts.FILE_TYPE_INFO : ze.getName()));

				if (ze.getName().contains(Consts.FILE_TYPE_PUZZLE))
					fout = Helper.openOutputStream(context,
							destPath + "/" + (isTemp ? "puzzle" + Consts.FILE_TYPE_PUZZLE : ze.getName()));

				byte data[] = new byte[Consts.BUFFER];
				if (fout != null) {
					int count;
					while ((count = zin.read(data, 0, Consts.BUFFER)) != -1) {
						fout.write(data, 0, count);
					}
				}

				zin.closeEntry();
				if (fout != null)
					fout.close();
			}
			zin.close();
		} catch (Exception e) {
			Log.e("Decompress", e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				if (fout != null)
					fout.close();
			} catch (IOException e) {
				Log.e("Decompress", e.getMessage());
				e.printStackTrace();
			}
		}
	}

	public static void createConfigFile(Context context, File file) {
		if (!file.exists()) {
			DataOutputStream dos = null;
			try {
				dos = new DataOutputStream(new FileOutputStream(file));
				dos.writeInt(0);
			} catch (IOException e) {
				Helper.doMessageDialog(context, context.getPackageName(),
						"Unable to create configuration files.\nTry to restart the Application");
				e.printStackTrace();
			} finally {
				try {
					if (dos != null)
						dos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public static boolean registerPuzzle(Context context, String filePath, String data) {
		DataInputStream dis = null;
		int number = 0;
		String[] puzzleIds = new String[0];
		try {
			dis = new DataInputStream(Helper.openInputStream(context, filePath));
			number = dis.readInt();
			puzzleIds = new String[number];

			for (int i = 0; i < number; ++i) {
				puzzleIds[i] = dis.readUTF();
			}
		} catch (IOException e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
			return false;
		} finally {
			try {
				if (dis != null)
					dis.close();
			} catch (IOException e) {
				System.out.println(e.getMessage());
				e.printStackTrace();
				return false;
			}
		}

		for (int i = 0; i < number; ++i) {
			if (puzzleIds[i].equals(data))
				return false;
		}

		DataOutputStream dos = null;
		try {
			dos = new DataOutputStream(Helper.openOutputStream(context, filePath));
			dos.writeInt(number + 1);
			for (int i = 0; i < number; ++i) {
				dos.writeUTF(puzzleIds[i]);
			}
			dos.writeUTF(data);
		} catch (IOException e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
			return false;
		} finally {
			try {
				if (dos != null)
					dos.close();
			} catch (IOException e) {
				System.out.println(e.getMessage());
				e.printStackTrace();
				return false;
			}
		}

		return true;
	}

	public static boolean unRegisterPuzzle(Context context, String filePath, String data) {
		DataInputStream dis = null;
		int number = 0;
		String[] puzzleIds = new String[0];
		try {
			dis = new DataInputStream(Helper.openInputStream(context, filePath));
			number = dis.readInt();
			puzzleIds = new String[number];

			for (int i = 0; i < number; ++i) {
				puzzleIds[i] = dis.readUTF();
			}
		} catch (IOException e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
			return false;
		} finally {
			try {
				if (dis != null)
					dis.close();
			} catch (IOException e) {
				System.out.println(e.getMessage());
				e.printStackTrace();
				return false;
			}
		}

		int dataIndex = -1;
		for (int i = 0; i < number; ++i) {
			if (puzzleIds[i].equals(data)) {
				dataIndex = i;
				break;
			}
		}

		if (dataIndex < 0)
			return false;

		DataOutputStream dos = null;
		try {
			dos = new DataOutputStream(Helper.openOutputStream(context, filePath));
			dos.writeInt(number - 1);
			for (int i = 0; i < number; ++i) {
				if (i == dataIndex)
					continue;

				dos.writeUTF(puzzleIds[i]);
			}
		} catch (IOException e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
			return false;
		} finally {
			try {
				if (dos != null)
					dos.close();
			} catch (IOException e) {
				System.out.println(e.getMessage());
				e.printStackTrace();
				return false;
			}
		}

		return true;
	}

	public static String[] getPuzzleData(Context context, String filePath) {
		DataInputStream dis = null;
		String[] puzzleIds = null;
		try {
			dis = new DataInputStream(Helper.openInputStream(context, filePath));
			int number = dis.readInt();
			puzzleIds = new String[number];

			for (int i = 0; i < number; ++i) {
				puzzleIds[i] = dis.readUTF();
			}
		} catch (IOException e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
			return null;
		} finally {
			try {
				if (dis != null)
					dis.close();
			} catch (IOException e) {
				System.out.println(e.getMessage());
				e.printStackTrace();
				return null;
			}
		}

		return puzzleIds;
	}

	public static boolean savePuzzleData(Context context, String filePath, String[] data) {
		DataOutputStream dos = null;
		try {
			dos = new DataOutputStream(Helper.openOutputStream(context, filePath));
			dos.writeInt(data.length);
			for (int i = 0; i < data.length; ++i) {
				dos.writeUTF(data[i]);
			}
		} catch (IOException e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
			return false;
		} finally {
			try {
				if (dos != null)
					dos.close();
			} catch (IOException e) {
				System.out.println(e.getMessage());
				e.printStackTrace();
				return false;
			}
		}

		return true;
	}

	public static boolean updateAccountBalance(BaseActivity context, String filePath, int credit) {
		DataInputStream dis = null;
		DataOutputStream dos = null;
		int currentBalance = 0;

		try {
			dis = new DataInputStream(Helper.openInputStream(context, filePath));
			currentBalance = dis.readInt();
		} catch (IOException e) {
			Helper.doMessageDialog(context, context.getLocalClassName(),
					"Unable to access to your account balance.\nTry to restart the Application");
			System.out.println(e.getMessage());
			e.printStackTrace();
			return false;
		} finally {
			try {
				if (dis != null)
					dis.close();
			} catch (IOException e) {
				Helper.doMessageDialog(context, context.getLocalClassName(),
						"Unable to access to your account balance.\nTry to restart the Application");
				System.out.println(e.getMessage());
				e.printStackTrace();
				return false;
			}
		}

		if (credit < 0 && credit + currentBalance < 0) {
			Helper.doMessageDialog(context, context.getLocalClassName(), "You do not have enough credits.");
			return false;
		}

		try {
			currentBalance += credit;
			dos = new DataOutputStream(Helper.openOutputStream(context, filePath));
			dos.writeInt(currentBalance);
		} catch (IOException e) {
			Helper.doMessageDialog(context, context.getLocalClassName(),
					"Unable to access to your account balance.\nTry to restart the Application");
			System.out.println(e.getMessage());
			e.printStackTrace();
			return false;
		} finally {
			try {
				if (dos != null)
					dos.close();
			} catch (IOException e) {
				Helper.doMessageDialog(context, context.getLocalClassName(),
						"Unable to access to your account balance.\nTry to restart the Application");
				System.out.println(e.getMessage());
				e.printStackTrace();
				return false;
			}
		}

		context.setCreditBalance(currentBalance);
		TextView creditBalanceField = (TextView) context.findViewById(R.id.credit_balance_field);
		if (creditBalanceField != null) {
			creditBalanceField.setText(currentBalance > 0 ? "" + currentBalance : "0");
		}
		return true;
	}
}